package org.Yiran.timetale_re.capability;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.network.PacketDistributor;
import org.Yiran.timetale_re.network.NetworkChannel;
import org.Yiran.timetale_re.network.SCResponsePacket;

/**
 * 符文制作熟练度能力类
 * 管理玩家的符文制作等级和经验值，实现等级升级逻辑和数据同步
 * <p>
 * 主要功能:
 * 1. 管理玩家的符文制作熟练度等级和经验值
 * 2. 实现经验值增加和等级升级逻辑
 * 3. 通过网络同步客户端和服务端数据
 * 4. 支持NBT序列化以便保存和加载
 */
public class RuneCraftingProficiency implements INBTSerializable<CompoundTag> {

    // ==================== 实例变量 ====================

    /** 熟练度等级 */
    private int proficiencyLevel = 0;

    /** 当前经验值 */
    private double experience = 0.0;

    /** 玩家引用 */
    private Player player;

    // ==================== 构造函数 ====================

    /**
     * 默认构造函数
     */
    public RuneCraftingProficiency() {
        // 默认构造函数
    }

    // ==================== 玩家引用管理 ====================

    /**
     * 设置玩家引用
     * 用于后续的数据同步操作
     *
     * @param player 玩家实体引用
     */
    public void setPlayer(Player player) {
        this.player = player;
    }

    // ==================== 获取器方法 ====================

    /**
     * 获取熟练度等级
     *
     * @return 当前熟练度等级
     */
    public int getProficiencyLevel() {
        return proficiencyLevel;
    }

    /**
     * 获取当前经验值
     *
     * @return 当前经验值
     */
    public double getExperience() {
        return experience;
    }

    // ==================== 经验值管理方法 ====================

    /**
     * 增加经验值
     * 自动检查是否可以升级，并同步到客户端
     *
     * @param exp 要增加的经验值
     */
    public void addExperience(double exp) {
        this.experience += exp;
        // 检查是否升级
        checkLevelUp();
        // 同步到客户端
        syncToClient();
    }

    /**
     * 直接设置经验值
     * 自动检查是否可以升级，并同步到客户端
     *
     * @param exp 要设置的经验值
     */
    public void setExperience(double exp) {
        this.experience = exp;
        checkLevelUp();
        // 同步到客户端
        syncToClient();
    }

    /**
     * 直接设置等级
     * 并同步到客户端
     *
     * @param level 要设置的等级
     */
    public void setProficiencyLevel(int level) {
        this.proficiencyLevel = level;
        // 同步到客户端
        syncToClient();
    }

    // ==================== 升级检查方法 ====================

    /**
     * 检查是否可以升级
     * 如果当前经验值足够升级，则自动提升等级
     */
    private void checkLevelUp() {
        while (experience >= getExperienceForNextLevel()) {
            proficiencyLevel++;
        }
    }

    // ==================== 经验值计算方法 ====================

    /**
     * 获取升级到下一级所需的经验值
     * 使用指数增长公式计算所需经验值
     *
     * @return 升级到下一级所需的总经验值
     */
    public double getExperienceForNextLevel() {
        return proficiencyLevel * 100 * Math.pow(1.1, proficiencyLevel);
    }

    /**
     * 获取升级到下一级所需的经验差值
     *
     * @return 当前经验值与下一级所需经验值的差值
     */
    public double getExperienceToNextLevel() {
        return getExperienceForNextLevel() - experience;
    }

    /**
     * 获取当前等级所需总经验（从0级到当前等级的累计经验）
     *
     * @return 从0级到当前等级的累计经验值
     */
    public double getExperienceForCurrentLevel() {
        double total = 0;
        for (int i = 0; i < proficiencyLevel; i++) {
            total += i * 100 * Math.pow(1.1, i);
        }
        return total;
    }

    // ==================== 网络同步方法 ====================

    /**
     * 同步数据到客户端
     * 只在服务端执行，向客户端发送同步数据包
     */
    private void syncToClient() {
        if (player != null && !player.level().isClientSide && player instanceof ServerPlayer serverPlayer) {
            NetworkChannel.CHANNEL.send(
                PacketDistributor.PLAYER.with(() -> serverPlayer),
                new SCResponsePacket.RuneProficiencySyncPacket(proficiencyLevel, experience)
            );
        }
    }

    // ==================== NBT序列化方法 ====================

    /**
     * 将能力数据序列化为NBT标签
     *
     * @return 包含等级和经验值的CompoundTag
     */
    @Override
    public CompoundTag serializeNBT() {
        CompoundTag tag = new CompoundTag();
        tag.putInt("ProficiencyLevel", proficiencyLevel);
        tag.putDouble("Experience", experience);
        return tag;
    }

    /**
     * 从NBT标签反序列化能力数据
     *
     * @param tag 包含等级和经验值的CompoundTag
     */
    @Override
    public void deserializeNBT(CompoundTag tag) {
        proficiencyLevel = tag.getInt("ProficiencyLevel");
        experience = tag.getDouble("Experience");
    }
}